use lazy_static::lazy_static;
use serde::{Deserialize, Serialize};

//核心
use jsonwebtoken::*;

use crate::CustomResult::{CustomResult,CustomError,ApiError};

use axum::{async_trait, extract::FromRequestParts, http::request::Parts as RequestParts};
use axum_extra::{
    extract::TypedHeader,
    headers::{authorization::Bearer, Authorization},
};

use std::time::{SystemTime,UNIX_EPOCH};

// use jsonwebtoken::{
//     decode, decode_header, encode, errors::Error, Algorithm, DecodingKey, EncodingKey, Header,
//     Validation,
// };

//懒加载的静态变量 JWT_SECRET 来自于 .env文件中的 JWT_SECRET 变量
lazy_static! {
    static ref JWT_SECRET: String = std::env::var("JWT_SECRET").expect("JWT_SECRET must be set");
}

//第一步： 定义一个 Claims 类型 ，它包含了 user_id 和 用户登录过期时间 exp 2个数据
#[derive(Serialize, Deserialize, Debug)]
pub struct Claims {
    pub user_id: i32, //用户id 
    pub exp: u64,     //过期时间 必须有该字段
}

//第二步: 申明一个名为 generate_jwt 函数 暴露给外部 ，让外部通过该函数可以产生jwt
pub fn generate_jwt(claims: &Claims) -> CustomResult<String> {
    println!("产生jwt时传入的claims=:{:?}", claims);
    let token = jsonwebtoken::encode (  
        & jsonwebtoken::Header::default(), //jwt的第一部分: header
        & claims, // //jwt的第二部分: claims
        &EncodingKey::from_secret(JWT_SECRET.as_ref()),//jwt的第三部分: 
    );

    token.map_err(Into::into)
}

//第三步: 为 Claims 实现 FromRequestParts trait
// Claims 实现 FromRequestParts trait 后, 可以在处理客户端请求时(handler中) 提取 客户端发送过来的jwt的claims部分
// 通过 指定 Rejection 的类型， 返回指定的错误类型
// 通过 from_request_parts 函数, 指明了客户端请求时 Authorization Bearer格式
#[async_trait]
impl<B> FromRequestParts<B> for Claims
where
    B: Send + Sync,
{
    type Rejection = CustomError;  //指定 from_request_parts 函数 返回的错误的类型 为 CustomError类型
    async fn from_request_parts(parts: &mut RequestParts, state: &B) -> Result<Self, Self::Rejection> {
        // 从请求的headers 中提取 {Authorization : Bearer jwt} 如果失败返回 UnAuth错误
        let TypedHeader(Authorization(bearer)) =
            TypedHeader::<Authorization<Bearer>>::from_request_parts(parts, state)
                .await
                .map_err(|_|CustomError::UnAuth)?;

        // 获取当前时间的 Unix 时间戳（秒）
        let now = SystemTime::now().duration_since(UNIX_EPOCH).expect("获取Unix当前时间失败").as_secs();
        
        // 创建验证配置，检查 'exp' 字段
        let mut validation = jsonwebtoken::Validation::default();
        validation.validate_exp = true;

        // 解码用户数据
        let token_data = decode::<Claims>(
            &bearer.token(),
            &DecodingKey::from_secret(JWT_SECRET.as_bytes()),
            &validation,
        ).map_err(|e| CustomError::JwtError(e))?;

        // 检查令牌中的 'exp' 字段是否在当前时间之前
        if token_data.claims.exp <= now {
             Err(ApiError::TokenExpiration.into())
        } else {
            Ok(token_data.claims)
        }
    }
}